package tools

import (
	"crypto/md5"
	"encoding/json"
	"fmt"
	"io"
	"math/rand"
	"net/url"
	"reflect"
	"strconv"
	"strings"
	"time"
)

func Md5(str string) string {
	if len(str) == 0 {
		return str
	}
	h := md5.New()
	_, _ = io.WriteString(h, str)
	return fmt.Sprintf("%x", h.Sum(nil))
}

func Implode(glue string, pieces []string) string {
	return strings.Join(pieces, glue)
}

func InArray(needle interface{}, haystack interface{}) bool {
	switch key := needle.(type) {
	case string:
		for _, item := range haystack.([]string) {
			if key == item {
				return true
			}
		}
	case int:
		for _, item := range haystack.([]int) {
			if key == item {
				return true
			}
		}
	case int64:
		for _, item := range haystack.([]int64) {
			if key == item {
				return true
			}
		}
	default:
		return false
	}
	return false
}

func RandCreator(l int) string {
	str := "0123456789abcdefghigklmnopqrstuvwxyz"
	strList := []byte(str)

	result := []byte{}
	i := 0

	r := rand.New(rand.NewSource(time.Now().UnixNano()))
	for i < l {
		newStr := strList[r.Intn(len(strList))]
		result = append(result, newStr)
		i = i + 1
	}
	return string(result)
}

func StructToUrlValues(fields interface{}, exclude []string) url.Values {
	t := reflect.TypeOf(fields)
	v := reflect.ValueOf(fields)

	signParams := url.Values{}
	for k := 0; k < t.NumField(); k++ {
		key := t.Field(k).Tag.Get("json")
		if InArray(key, exclude) {
			continue
		}
		switch t.Field(k).Type.String() {
		case "string":
			signParams.Add(
				key, fmt.Sprintf("%s", v.Field(k).Interface()),
			)
		case "int", "int64":
			signParams.Add(
				key, fmt.Sprintf("%d", v.Field(k).Interface()),
			)
		default:
			signParams.Add(
				key, fmt.Sprintf("%s", v.Field(k).Interface()),
			)
		}
	}
	return signParams
}

func AnyValueToString(value interface{}) string {
	var key string
	if value == nil {
		return key
	}

	switch value.(type) {
	case float64:
		ft := value.(float64)
		key = strconv.FormatFloat(ft, 'f', -1, 64)
	case float32:
		ft := value.(float32)
		key = strconv.FormatFloat(float64(ft), 'f', -1, 64)
	case int:
		it := value.(int)
		key = strconv.Itoa(it)
	case uint:
		it := value.(uint)
		key = strconv.Itoa(int(it))
	case int8:
		it := value.(int8)
		key = strconv.Itoa(int(it))
	case uint8:
		it := value.(uint8)
		key = strconv.Itoa(int(it))
	case int16:
		it := value.(int16)
		key = strconv.Itoa(int(it))
	case uint16:
		it := value.(uint16)
		key = strconv.Itoa(int(it))
	case int32:
		it := value.(int32)
		key = strconv.Itoa(int(it))
	case uint32:
		it := value.(uint32)
		key = strconv.Itoa(int(it))
	case int64:
		it := value.(int64)
		key = strconv.FormatInt(it, 10)
	case uint64:
		it := value.(uint64)
		key = strconv.FormatUint(it, 10)
	case string:
		key = value.(string)
	case []byte:
		key = string(value.([]byte))
	default:
		newValue, _ := json.Marshal(value)
		key = string(newValue)
	}

	return key
}

// Split 字符串s按照给定的分隔符sep进行分割返回字符串切片
func Split(s, sep string) []string {
	i := strings.Index(s, sep)

	var result []string
	for i > -1 {
		result = append(result, s[:i])
		s = s[i+1:]
		i = strings.Index(s, sep)
	}
	return append(result, s)
}
